/**
 * Copyright(c) 2014 Xunton Solutions
 *
 * History:
 *   15-1-27 上午9:26 Created by dwzhang
 */
package com.jade.modules.cms.impl;

import java.util.List;
import javax.ejb.TransactionAttribute;
import javax.inject.Inject;
import javax.inject.Named;

import com.jade.framework.base.criterion.Criteria;
import com.jade.framework.cache.CacheService;
import com.jade.framework.mom.MomConstants;
import com.jade.modules.cms.CmsException;
import com.jade.modules.cms.ContentCount;
import com.jade.modules.cms.ContentCountDao;
import com.jade.modules.cms.ContentCountManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;

/**
 * 内容计数管理器实现。
 *
 * @author <a href="mailto:dwzhang@xunton.com">dwzhang</a> 
 * @version 1.0 15-1-27 上午9:26
 */
//@Named ("module_cmsCountManager")
public class CountManagerImpl implements ContentCountManager
{
    protected CacheService cacheService;
    protected ContentCountDao countDao;
    protected static final String CACHE_PREFIX = "module.cms.content";
    protected static final String CACHE_COUNT = "count";
    protected static final String CACHE_FLAG = "flag";
    protected static final String MOM_TOPIC = "CMS_CONTENT_COUNT";
    protected static final int TIMEOUT = 24 * 3600;

    protected Log log = LogFactory.getLog(CountManagerImpl.class);
    protected int delayLevel = MomConstants.DELAY_LEVEL_2M;

//    @Inject
    public void setCountDao(@Named ("module_cmsCountDao") ContentCountDao countDao)
    {
        this.countDao = countDao;
    }

    public void setCacheService(CacheService cacheService)
    {
        this.cacheService = cacheService;
    }

    public ContentCount getCount(String entityType, long entityId)
    {
        return countDao.getCount(entityType, entityId);
    }

    public List<ContentCount> listCount(Criteria criteria)
    {
        return countDao.listCount(criteria);
    }

    public long getCount(String entityType, long entityId, String type)
    {
        ContentCount count = countDao.getCount(entityType, entityId);
        return count == null ? 0 : count.get(type);
//        //先取以前的汇总
//        ContentCount count = countDao.getCount(entityType, entityId);
//        //再取最近的更新
//
//        return count == null ? 0 : count.get(type) + DataUtils.getLong(
//                cacheService.get(getCountKey(entityType, entityId, type)),
//                0);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void addCount(String entityType, long entityId, String type, long count)
            throws CmsException
    {
        ContentCount countObj = new ContentCount();
        countObj.setEntityType(entityType);
        countObj.setEntityId(entityId);
        countObj.set(type, count);
        countDao.setCount(countObj, true);

//        //新增计数
//        String key = getCountKey(entityType, entityId, type);
//        if (count > 0) {
//            cacheService.incr(key, count, count, TIMEOUT);
//        }
//        else {
//            cacheService.decr(key, Math.abs(count), count, TIMEOUT);
//        }
//        //检查这个contentId是否已经在队列中
//        long flag = cacheService.incr(getFlagKey(entityType, entityId), 1, 1, TIMEOUT);
//        if (flag == 1) {
//            //需要添加一个定期更新的任务，使用队列
//            try {
//                MomUtils.send(MOM_TOPIC, entityType + "_" + String.valueOf(entityId), null, delayLevel, new Object[]{entityType, entityId});
//                log.info("Push a content count message to queue:" + entityType + " " + entityId);
//            }
//            catch (Throwable t) {
//                log.warn("Can't push content count topic to queue:", t);
//                cacheService.delete(getFlagKey(entityType, entityId));
//            }
//        }
    }

//    public ContentCount getCachedCount(String entityType, long entityId)
//    {
//        //先取以前的汇总
//        ContentCount count = countDao.getCount(entityType, entityId);
//        getFromCache(count);
//        return count;
//    }
//
//    @TransactionAttribute
//    @Transactional (rollbackFor = Throwable.class)
//    public void consumeMessage(List<MomMessage> messages)
//    {
//        List<ContentCount> counts = new ArrayList<ContentCount>();
//
//        for (MomMessage message : messages) {
//            Object[] array = (Object[]) message.getMsg();
//            String entityType = (String) array[0];
//            long entityId =  DataUtils.getLong(array[1], 0);
//            log.info("Pop a content count message from queue:" + entityType + " " + entityId);
//            if (StringUtils.isBlank(entityType) || entityId == 0) {
//                continue;
//            }
//            ContentCount count = new ContentCount();
//            count.setEntityType(entityType);
//            count.setEntityId(entityId);
//            getFromCache(count);
//            counts.add(count);
//        }
//        for (ContentCount count : counts) {
//            if (count.isAllZero()) {
//                continue;
//            }
//
//            //先从cache中减掉数量，因为cache效率高
//            updateToCache(count, false);
//            try {
//                //更改数据库中的变量
//                countDao.setCount(count, true);
//            }
//            catch (Throwable t) {
//                //更新数据库失败，重新把cache中的数量加回
//                log.warn("Can't update count:", t);
//                updateToCache(count, true);
//            }
//        }
//
//        //更新内容的业务标记
//        removeFlag(counts);
//    }
//
//    public void setDelayLevel(int delayLevel)
//    {
//        this.delayLevel = delayLevel;
//    }
//
//    protected String getCountKey(String entityType, long entityId, String type)
//    {
//        return CacheUtils.joinKey(CACHE_PREFIX, entityType, String.valueOf(entityId), CACHE_COUNT, type);
//    }
//
//    protected String getFlagKey(String entityType, long entityId)
//    {
//        return CacheUtils.joinKey(CACHE_PREFIX, entityType, String.valueOf(entityId), CACHE_FLAG);
//    }
//
//    protected void removeFlag(List<ContentCount> counts)
//    {
//        for (ContentCount count : counts) {
//            try {
//                cacheService.delete(getFlagKey(count.getEntityType(), count.getEntityId()));
//            }
//            catch (Throwable t) {
//                //todo 移除失败，可能导致一个内容的数量不被更新到
//                log.warn("Can't remove content flag for " + count.getEntityType() + " " + count.getEntityId(), t);
//            }
//        }
//    }
//
//    protected void updateToCache(ContentCount count, boolean increase)
//    {
//        for (String type : ContentCount.TYPES) {
//            updateToCache(count, type, increase);
//        }
//    }
//
//    protected void updateToCache(ContentCount count, String type, boolean increase)
//    {
//        long c = count.get(type);
//        if (c == 0) {
//            return;
//        }
//
//        try {
//            if (increase) {
//                cacheService.incr(getCountKey(count.getEntityType(), count.getEntityId(), type), c, TIMEOUT);
//            }
//            else {
//                cacheService.decr(getCountKey(count.getEntityType(), count.getEntityId(), type), c, TIMEOUT);
//            }
//        }
//        catch (Throwable t) {
//            log.warn("Can't decr content count for type:" + type);
//            count.set(type, 0);
//        }
//    }
//
//    protected void getFromCache(ContentCount count)
//    {
//        String[] keys = new String[ContentCount.TYPES.length];
//        for (int i = 0; i < keys.length; i++) {
//            keys[i] = getCountKey(count.getEntityType(), count.getEntityId(), ContentCount.TYPES[i]);
//        }
//        try {
//            //如果计数器是负数，通过getBulk取将取不到，暂时只能通过计数器为0的方式单个取
//            //Map<String, Object> values = cacheService.getBulk(keys);
//            for (int i = 0; i < keys.length; i++) {
//                count.set(ContentCount.TYPES[i],
//                        DataUtils.getLong(values.get(keys[i]), 0) + count.get(ContentCount.TYPES[i]));
//            }
//        }
//        catch (Throwable t) {
//            log.warn("Can't get content count for :" + count.getEntityType() + " " + count.getEntityId(), t);
//        }
//    }
}
